package hk.polyu.dds;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.Map.Entry;

import android.os.*;
import android.util.Log;


public class DataServer extends Thread{

	private Handler 		mHandler;
	private ServerSocket 	mServerSocket;
	private List<Socket>	mClientSockets = new ArrayList<Socket>();
	
	private HashMap<String, Socket>	mClients = new HashMap<String, Socket>();
	
	private	boolean			mIsRuning = true;
	
	public DataServer(Handler h) {
		mHandler = h;
	}
	
	public HashMap<String, Socket> getClient() {
		return this.mClients;
	}
	
	/**
	 * Send the data collection command to all clients.
	 */
	public void sendCollectionRequest() {
		Iterator<Entry<String, Socket>> it = this.mClients.entrySet().iterator();
	    while (it.hasNext()) {
	        Entry<String, Socket> pairs = it.next();
	        
	        try {
		        Socket s = pairs.getValue();
		        OutputStreamWriter osw = new OutputStreamWriter(s.getOutputStream());
		        String str = String.format("BEGN %d\r\n", System.currentTimeMillis());
				osw.write(str);
		        osw.flush();
		        Log.d("polyu", "Server send " + pairs.getKey() + " " + str);
			} catch (IOException e) {
				e.printStackTrace();
			}
	    }
	}
	
	

	public void sendStopRequest() {
		Iterator<Entry<String, Socket>> it = this.mClients.entrySet().iterator();
	    while (it.hasNext()) {
	        Entry<String, Socket> pairs = it.next();
	        
	        try {
		        Socket s = pairs.getValue();
		        OutputStreamWriter osw = new OutputStreamWriter(s.getOutputStream());
		        String str = String.format("ENDS %d\r\n", 0);
				osw.write(str);
		        osw.flush();
		        Log.d("polyu", "Server send " + pairs.getKey() + " " + str);
		        // Do NOT close socket here
		        
		        //osw.close();
		        //s.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    }
	}
	
	
	
	@Override
	public void run() {
		
		
		try {
			mServerSocket = new ServerSocket(9988);
	        Log.d("polyu", "Server: Socket opened with IP :" + mServerSocket.getInetAddress().toString());
	        
	        while(mIsRuning == true) {
		        Socket client = mServerSocket.accept();

		        this.mClientSockets.add(client);
		        
		        // create thread for each client
		        ClientHandleThread ct = new ClientHandleThread(client, this.mHandler);
		        ct.start();
		        
		        Log.d("polyu", "Server: client connected");
	        }
	        
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	
	public void stopServer() {
		this.mIsRuning = false;
		
		// close all clients and server
		try {
			for(Socket s : this.mClientSockets) {
				s.close();
			}
			mServerSocket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * Inner class. One thread for each client.
	 * @author hezongjian
	 *
	 */
	class ClientHandleThread extends Thread{
		
		private Handler 	mHandler;
		private Socket 		mSocket;
		private BufferedReader	mReader;
		private BufferedWriter	mWriter = null;
		
		public ClientHandleThread(Socket s, Handler h) {
			mHandler = h;
			mSocket = s;
		}
		
		@Override
		public void run() {
			
			try {
				mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
				mWriter = new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream()));
				
				// listen to client data.
				String line = mReader.readLine();
				Log.d("polyu", "Server recieved: " + line);
				
				// split the content into parts
				String[] parts = line.split(" ");
				
				if (parts[0].equalsIgnoreCase("CONN")) {
					// remeber client ID and send back the server time.
					String cid = parts[1];
					mClients.put(cid, mSocket);
					long ctime = System.currentTimeMillis();
					mWriter.write(String.format("OKOK %d\r\n", ctime));
					mWriter.flush();
					
			        // Notify main thread.
			        this.mHandler.sendEmptyMessage(MainUI.MSG_CLIENTCONNECTED);
					
				} else if (parts[0].equalsIgnoreCase("DATA")) {
					// send data here.
					
				}
				
				/*
				mWriter.close();
				mReader.close();
				mSocket.close();
				*/
				
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			
		}
		
	}
	

}
